/*******************************************************************************
 FileName:      streamBuff.c
 Author:        urey
 Version :      1.0
 Date:          2015年8月4日
 Description:
 History:
 <author>		<time>			<version >      <desc>
 urey        2015年8月4日          1.0          create
 *******************************************************************************/

#include "streamBuff.h"

/**
 * 获取StreamNode，先查看freeStreamList，若没有不用的StreamNode，则进行内存分配
 * @param pFreeStreamList
 * @param ppStreamNode
 * @param pMemoryPool
 * @return  STREAMBUFF_NULL_ERROR    空指针错误
 *          STREAMBUFF_NULLNODE_ERROR 空节点错误，可能需要重建缓存来修复
 *          STREAMBUFF_MEM_ERROR     内存分配失败，致命错误
 */
static Int32 initStreamNode(S_StreamList* pFreeStreamList, S_StreamNode** ppStreamNode, S_StmMemPool* pMemoryPool, Uint16 buffSize)
{
    S_StreamNode* pTempStreamNode = NULL;
    if(ppStreamNode == NULL)
    {
        return STREAMBUFF_NULL_ERROR;
    }
    do
    {
        if(pFreeStreamList == NULL || linkedListIsEmpty(pFreeStreamList))
        {
            break;
        }
        S_StreamListNode* pTempListNode = linkedListGetFirst(pFreeStreamList);
        if(pTempListNode == NULL)
        {
            break;
        }
        pTempStreamNode = pTempListNode->value;
        assert(pTempStreamNode->StreamLinkNode.value == pTempStreamNode);
        if(pTempStreamNode == NULL || pTempStreamNode->StreamLinkNode.value != pTempStreamNode)
        {
            break;
        }
        linkedListRemoveNode(&pTempStreamNode->StreamLinkNode);
        *ppStreamNode = pTempStreamNode;
        return STREAMBUFF_SUCCESS;
    }while(0);
    if(pMemoryPool == NULL)
    {
        return STREAMBUFF_NULL_ERROR;
    }
    pTempStreamNode = (S_StreamNode*)apr_palloc(pMemoryPool, sizeof(S_StreamNode) + buffSize);
    if(pTempStreamNode == NULL)
    {
        return STREAMBUFF_MEM_ERROR;
    }
    memset(pTempStreamNode, 0, buffSize + sizeof(S_StreamNode));
    pTempStreamNode->StreamLinkNode.value = pTempStreamNode;
    *ppStreamNode = pTempStreamNode;
    return STREAMBUFF_SUCCESS;
}

/* 将PktBuffNode从链表中删除，并放入freeList中 */
static void delStreamNode(S_StreamBuff* pStreamBuff, S_StreamNode* pStreamNode)
{
    if(pStreamNode == NULL)
    {
        return;
    }
    linkedListRemoveNode(&pStreamNode->StreamLinkNode);
    memset((char*)(pStreamNode + 1), 0, pStreamBuff->buffSize);
    pStreamNode->endPos = pStreamNode->startPos = 0;
    linkedListAddFirst(&pStreamBuff->freeStreamList, &pStreamNode->StreamLinkNode);
    return;
}

/**
 * 将数据放入StreamBuff中，若当前StreamNode还可写入则直接写入，若StreamNode无法写入，则初始化新的StreamNode
 * @param pStreamBuff
 * @param pData             添加流数据地址
 * @param DataLen           添加的数据长度
 * @return  STREAMBUFF_NULLNODE_ERROR
 *          STREAMBUFF_MEM_ERROR
 */
Int32 addStreamDataCore(S_StreamBuff* pStreamBuff, char* pData, Int32 DataLen)
{
    if(pStreamBuff == NULL || pData == NULL)
    {
        return STREAMBUFF_NULL_ERROR;
    }
    Int32 leftDataLen = DataLen;
    S_StreamNode* pStreamNode =NULL;
    S_StmMemPool* pStreamPool = pStreamBuff->pStreamPool;
    Uint16 stmBuffSize = pStreamBuff->buffSize;
    S_StreamListNode* pStreamListNode = NULL;
    S_StreamList* pWaitStreamList = &pStreamBuff->waitStreamList;
    S_StreamList* pFreeStreamList = &pStreamBuff->freeStreamList;
    do
    {
        /* 取出最后一个StreamNode查看是否还能够放入数据 */
        if(linkedListIsEmpty(pWaitStreamList))
        {
            break;
        }
        pStreamListNode = linkedListGetFirst(pWaitStreamList);
        if(pStreamListNode == NULL)
        {
            return STREAMBUFF_NULLNODE_ERROR;
        }
        pStreamNode = pStreamListNode->value;
        if(stmBuffSize - pStreamNode->endPos  > 0) /* 还能够放入数据则进行放入 */
        {
            Int32 spaceLeft = pStreamBuff->buffSize - pStreamNode->endPos;
            Int32 moveLen = min(spaceLeft, leftDataLen);
            assert((pStreamNode->endPos + moveLen) <= pStreamBuff->buffSize);
            memcpy((char*)(pStreamNode + 1) + pStreamNode->endPos, pData, moveLen);
            pStreamNode->endPos += moveLen;
            pData += moveLen;
            leftDataLen -= moveLen;
            pStreamBuff->totStoreSize += moveLen;
        }
    }while(0);
    /* 如果剩余的数据长度依然大于0，则需要申请新的stream空间来存放 */
    while(leftDataLen > 0)
    {
        pStreamNode = NULL;
        /*pStreamNodeValue = NULL;*/
        if(STREAMBUFF_SUCCESS != initStreamNode(pFreeStreamList, &pStreamNode, pStreamPool, stmBuffSize))
        {
            return STREAMBUFF_MEM_ERROR;
        }
        /*pStreamNodeValue = linkedListEntry(pStreamNode);*/
        Int32 spaceLeft = stmBuffSize - pStreamNode->endPos;
        Int32 moveLen = min(spaceLeft, leftDataLen);
        assert((pStreamNode->endPos + moveLen) <= stmBuffSize);
        memcpy((char*)(pStreamNode + 1) + pStreamNode->endPos, pData, moveLen);
        pStreamNode->endPos += moveLen;
        /* spaceLeft -= moveLen; */
        pData += moveLen;
        leftDataLen -= moveLen;
        pStreamBuff->totStoreSize += moveLen;
        linkedListAddFirst(pWaitStreamList, &pStreamNode->StreamLinkNode);
    }
    return STREAMBUFF_SUCCESS;
}

/**
 * 从StreamBuff的指定offset偏移字节开始，读取一段长度的数据，放入pData指向的空间中
 * @param pStreamBuff
 * @param offset        读取流的起始偏移
 * @param pData         存放读取数据的地址指针
 * @param readDataLen   读取流的长度
 * @return
 */
Int32 readStreamDataCore(S_StreamBuff* pStreamBuff, Int32 offset, char* pData, Int32 readDataLen)
{
    if(pStreamBuff == NULL || pData == NULL)
    {
        return STREAMBUFF_NULL_ERROR;
    }
    S_StreamList* pWaitStreamList = &pStreamBuff->waitStreamList;
    Int32 totMovedLen = 0;
    Int32 nodeOffset = 0;
    Int32 leftDataLen = readDataLen;
    /* 先找到offset对应的StreamNode */
    if(offset >= pStreamBuff->totStoreSize || leftDataLen == 0)
    {
        return STREAMBUFF_SUCCESS;
    }
    if(linkedListIsEmpty(pWaitStreamList))
    {
        return STREAMBUFF_EXPEMPTY_ERROR;
    }
    S_StreamListNode* pStreamListNode = linkedListGetTail(pWaitStreamList);
    S_StreamNode* pStreamNode = NULL;
    do
    {
        if(pStreamListNode == NULL)
        {
            /*ts_Log_error(STREAMBUFF_TAG, "Get NULL Node in Not Empty List!");*/
            return STREAMBUFF_NULLNODE_ERROR;
        }
        if(pStreamListNode == &pWaitStreamList->head)
        {
            /*ts_Log_error(STREAMBUFF_TAG, "StreamBuff size error!");*/
            return STREAMBUFF_EXPEMPTY_ERROR;
        }
        pStreamNode = pStreamListNode->value;
        Int32 nodeSize = pStreamNode->endPos - pStreamNode->startPos;
        if(offset < (nodeOffset + nodeSize))
        {
            break;
        }
        nodeOffset += nodeSize;
        pStreamListNode = pStreamListNode->prev;
    }while(1);
    /* 到此已经找到Offset之后的起始所在的StreamNode，在这之前的stream总长为nodeOffset */
    Int32 leftStreamLen = pStreamBuff->totStoreSize - offset;
    Int32 nodeStart = offset - nodeOffset;             /* 当前node应该读取数据报的起始位置 */
    Int32 StreamNodeLen = pStreamNode->endPos - (pStreamNode->startPos + nodeStart);
    if(StreamNodeLen < 0)
    {
        /*ts_Log_error(STREAMBUFF_TAG, "Error StreamLen:%d!", StreamNodeLen);*/
        assert(0);
        return STREAMBUFF_MEM_ERROR;
    }
    Int32 moveLen = min(StreamNodeLen, leftDataLen);
    assert((pStreamNode->startPos + moveLen) <= pStreamNode->endPos);
    assert(pStreamNode->endPos <= pStreamBuff->buffSize);
    memcpy(pData, (char*)(pStreamNode + 1) + pStreamNode->startPos + nodeStart, moveLen);
    leftDataLen -= moveLen;
    leftStreamLen -= moveLen;
    pData += moveLen;
    totMovedLen += moveLen;
    pStreamListNode = pStreamListNode->prev;
    /* 移动完第一个node中的数据，移动后续node中的数据 */
    while((leftDataLen > 0) && (leftStreamLen > 0))
    {
        if(pStreamListNode == NULL)
        {
            /*ts_Log_error(STREAMBUFF_TAG, "Get NULL Node in Not Empty List!");*/
            return STREAMBUFF_NULLNODE_ERROR;
        }
        if(pStreamListNode == &pWaitStreamList->head)
        {
            /*ts_Log_error(STREAMBUFF_TAG, "StreamBuff size error!");*/
            return STREAMBUFF_EXPEMPTY_ERROR;
        }
        S_StreamNode* pStreamNode = pStreamListNode->value;
        Int32 StreamLen = pStreamNode->endPos - pStreamNode->startPos;
        if(StreamLen < 0)
        {
            /*ts_Log_error(STREAMBUFF_TAG, "Error StreamLen:%d!", StreamLen);*/
            assert(0);
            return STREAMBUFF_MEM_ERROR;
        }
        Int32 moveLen = min(StreamLen, leftDataLen);
        assert((pStreamNode->startPos + moveLen) <= pStreamNode->endPos);
        assert(pStreamNode->endPos <= pStreamBuff->buffSize);
        memcpy(pData, (char*)(pStreamNode + 1) + pStreamNode->startPos, moveLen);
        leftDataLen -= moveLen;
        leftStreamLen -= moveLen;
        pData += moveLen;
        totMovedLen += moveLen;
        pStreamListNode = pStreamListNode->prev;
    }
    return totMovedLen;
}


/**
 * 从StreamBuff的起始删除一段长度的缓存数据
 * @param pStreamBuff       指向streamBuff的结构
 * @param delDataLen        需要删除的数据流长度
 * @param pFreeStreamList   存储free链表结构的队列指针
 * @return
 */
Int32 deleteStreamDataCore(S_StreamBuff* pStreamBuff, Int32 delDataLen)
{
    S_StreamList* pWaitStreamList = &pStreamBuff->waitStreamList;
    Int32 totMovedLen = 0;
    Int32  leftDataLen = delDataLen;
    while((leftDataLen > 0) && (pStreamBuff->totStoreSize > 0))
    {
        if(linkedListIsEmpty(pWaitStreamList))
        {
            return STREAMBUFF_EXPEMPTY_ERROR;
        }
        S_StreamNode* pStreamNode = linkedListGetTail(pWaitStreamList)->value;
        if(pStreamNode == NULL)
        {
            /*ts_Log_error(STREAMBUFF_TAG, "Get NULL Node in Not Empty List!");*/
            return STREAMBUFF_NULLNODE_ERROR;
        }
        /* 从StreamNode中获取数据 */
        Int32 StreamLen = pStreamNode->endPos - pStreamNode->startPos;
        if(StreamLen < 0)
        {
            /*ts_Log_error(STREAMBUFF_TAG, "Error StreamLen:%d!", StreamLen);*/
            assert(0);
            return STREAMBUFF_MEM_ERROR;
        }
        Int32 moveLen = min(StreamLen, leftDataLen);
        assert((pStreamNode->startPos + moveLen) <= pStreamNode->endPos);
        assert(pStreamNode->endPos <= pStreamBuff->buffSize);
        leftDataLen -= moveLen;
        pStreamBuff->totStoreSize -= moveLen;
        pStreamNode->startPos += moveLen;
        totMovedLen += moveLen;
        if(pStreamNode->startPos == pStreamBuff->buffSize)
        {
            delStreamNode(pStreamBuff, pStreamNode);
        }
    }
    return totMovedLen;
}
